package com.mdd.front.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.mdd.common.core.AjaxResult;
import com.mdd.common.entity.RechargeOrder;
import com.mdd.common.entity.VipRecord;
import com.mdd.common.entity.coupon.Coupon;
import com.mdd.common.entity.distribution.Distribution;
import com.mdd.common.entity.distribution.DistributionLevel;
import com.mdd.common.entity.goods.Goods;
import com.mdd.common.entity.order.Order;
import com.mdd.common.entity.order.OrderGoods;
import com.mdd.common.entity.setting.DevPayConfig;
import com.mdd.common.entity.setting.DevPayWay;
import com.mdd.common.entity.user.User;
import com.mdd.common.entity.user.UserAuth;
import com.mdd.common.enums.ClientEnum;
import com.mdd.common.enums.LogMoneyEnum;
import com.mdd.common.enums.NoticeEnum;
import com.mdd.common.enums.OrderEnum;
import com.mdd.common.enums.OrderLogEnum;
import com.mdd.common.enums.PaymentEnum;
import com.mdd.common.exception.OperateException;
import com.mdd.common.exception.PaymentException;
import com.mdd.common.mapper.LogIntegralMapper;
import com.mdd.common.mapper.RechargeOrderMapper;
import com.mdd.common.mapper.VipRecordMapper;
import com.mdd.common.mapper.coupon.CouponMapper;
import com.mdd.common.mapper.distribution.DistributionLevelMapper;
import com.mdd.common.mapper.distribution.DistributionMapper;
import com.mdd.common.mapper.goods.GoodsMapper;
import com.mdd.common.mapper.log.LogEarningsMapper;
import com.mdd.common.mapper.log.LogMoneyMapper;
import com.mdd.common.mapper.log.LogOrderMapper;
import com.mdd.common.mapper.order.OrderGoodsMapper;
import com.mdd.common.mapper.order.OrderMapper;
import com.mdd.common.mapper.setting.DevPayConfigMapper;
import com.mdd.common.mapper.setting.DevPayWayMapper;
import com.mdd.common.mapper.user.UserAuthMapper;
import com.mdd.common.mapper.user.UserMapper;
import com.mdd.common.pay.alipay.AliPayConfigUtils;
import com.mdd.common.pay.alipay.AlipayHandle;
import com.mdd.common.pay.wxpay.WxConfig;
import com.mdd.common.pay.wxpay.WxPayConfigUtils;
import com.mdd.common.pay.wxpay.WxpayHandle;
import com.mdd.common.plugin.alipay.AliPayDriver;
import com.mdd.common.plugin.alipay.request.AliPaymentRequest;
import com.mdd.common.plugin.notice.NoticeDriver;
import com.mdd.common.plugin.notice.vo.NoticeSmsVo;
import com.mdd.common.plugin.wechat.WxPayDriver;
import com.mdd.common.plugin.wechat.request.PaymentRequestV3;
import com.mdd.common.util.ConfigUtils;
import com.mdd.common.util.MapUtils;
import com.mdd.common.util.RequestUtils;
import com.mdd.common.util.StringUtils;
import com.mdd.common.util.TimeUtils;
import com.mdd.common.util.ToolUtils;
import com.mdd.common.util.UrlUtils;
import com.mdd.common.util.YmlUtils;
import com.mdd.common.util.em.EMServiceUtil;
import com.mdd.front.service.IDistributionService;
import com.mdd.front.service.IOrderService;
import com.mdd.front.service.IPayService;
import com.mdd.front.service.ISeckillService;
import com.mdd.front.validate.PaymentValidate;
import com.mdd.front.vo.pay.PayStatusVo;
import com.mdd.front.vo.pay.PayWayInfoVo;
import com.mdd.front.vo.pay.PayWayListVo;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class PayServiceImpl implements IPayService {

	@Resource
	UserMapper userMapper;

	@Resource
	UserAuthMapper userAuthMapper;

	@Resource
	DevPayWayMapper devPayWayMapper;

	@Resource
	DevPayConfigMapper devPayConfigMapper;

	@Resource
	RechargeOrderMapper rechargeOrderMapper;

	@Resource
	OrderMapper orderMapper;

	@Resource
	OrderGoodsMapper orderGoodsMapper;

	@Resource
	GoodsMapper goodsMapper;

	@Resource
	LogMoneyMapper logMoneyMapper;

	@Resource
	LogOrderMapper logOrderMapper;

	@Resource
	ISeckillService iSeckillService;

	@Resource
	IOrderService iOrderService;

	@Resource
	IDistributionService iDistributionService;

	// 等级规格
	@Resource
	DistributionLevelMapper distributionLevelMapper;
	@Resource
	DistributionMapper distributionMapper;
	@Resource
	LogEarningsMapper logEarningsMapper;

	@Resource
	DataSourceTransactionManager transactionManager ;

	@Resource
	TransactionDefinition transactionDefinition;
	@Resource
	LogIntegralMapper logIntegralMapper;
	@Resource
	CouponMapper couponMapper;


	@Resource
	AlipayHandle alipayHandle;
	@Resource
	WxpayHandle wxpayHandle;
	@Autowired
	WxConfig wxConfig;

	/**
	 * 支付方式
	 *
	 * @author fzr
	 * @param from 场景
	 * @param orderId 订单ID
	 * @param terminal 终端
	 * @return List<PayWayListedVo>
	 */
	@Override
	public PayWayListVo payWay(String from, Integer orderId, Integer terminal, Integer userId) {
		List<DevPayWay> devPayWays = devPayWayMapper.selectList(
				new QueryWrapper<DevPayWay>()
				.eq("scene", terminal)
				.eq("status", 1));

		PayWayListVo vo = new PayWayListVo();
		if (from.equals("recharge")) {
			RechargeOrder rechargeOrder = rechargeOrderMapper.selectById(orderId);
			vo.setOrderAmount(rechargeOrder.getOrderAmount());
		}

		if (from.equals("order")) {
			Order order = orderMapper.selectById(orderId);
			vo.setOrderAmount(order.getNeedPayMoney());
			// 订单允许取消时间
			vo.setCancelTime(iOrderService.getCancelUnpaidOrderTime(order.getCreateTime()));
		}

		Integer walletType = PaymentEnum.WALLET_PAY.getCode();
		List<PayWayInfoVo> list = new LinkedList<>();
		for (DevPayWay way : devPayWays) {
			if (from.equals("recharge") && way.getPayConfigId().equals(walletType)) {
				continue;
			}

			DevPayConfig devPayConfig = devPayConfigMapper.selectById(way.getPayConfigId());
			PayWayInfoVo infoVo = new PayWayInfoVo();
			infoVo.setId(devPayConfig.getId());
			infoVo.setName(devPayConfig.getName());
			infoVo.setIcon(UrlUtils.toAbsoluteUrl(devPayConfig.getIcon()));
			infoVo.setIsDefault(way.getIsDefault());
			list.add(infoVo);
		}
		vo.setList(list);

		// 用户余额
		User user = userMapper.selectById(userId);
		vo.setUserMoney(user.getMoney());

		return vo;
	}

	/**
	 * 订单状态
	 *
	 * @author fzr
	 * @param from 场景
	 * @param orderId 订单ID
	 * @return PayStatusVo
	 */
	@Override
	public PayStatusVo payStatus(String from, Integer orderId) {
		PayStatusVo vo = new PayStatusVo();
		boolean orderExist = false;

		switch (from) {
		case "recharge":
			RechargeOrder rechargeOrder = rechargeOrderMapper.selectById(orderId);
			if (StringUtils.isNotNull(rechargeOrder)) {
				orderExist = true;
				vo.setPayStatus(rechargeOrder.getPayStatus());
				vo.setPayWay(PaymentEnum.getPayWayMsg(rechargeOrder.getPayWay()));
				vo.setOrderId(rechargeOrder.getId());
				vo.setOrderSn(rechargeOrder.getOrderSn());
				vo.setOrderAmount(rechargeOrder.getOrderAmount());
				vo.setPayTime(StringUtils.isNotEmpty(vo.getPayTime()) ? TimeUtils.timestampToDate(vo.getPayTime()) : "");
			}
			break;
		case "order":
			Order order = orderMapper.selectById(orderId);
			if (StringUtils.isNotNull(order)) {
				orderExist = true;
				vo.setPayStatus(order.getPayIs());
				vo.setPayWay(PaymentEnum.getPayWayMsg(order.getPayWay()));
				vo.setOrderId(order.getId());
				vo.setOrderSn(order.getOrderSn());
				vo.setOrderAmount(order.getNeedPayMoney());
				vo.setPayTime(StringUtils.isNotNull(order.getPayTime()) ? TimeUtils.timestampToDate(order.getPayTime()) : "");
			}
			break;
		}

		if (!orderExist) {
			throw new OperateException("订单不存在!");
		}

		return vo;
	}

	private String getOpenidMnp(String code) {

		String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
				"wx03d3a4501c174a80", "b5ba2c574608a0fa9a3d3a2f31202a13", code);

		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpGet httpGet = new HttpGet(url);
		HttpResponse response;
		try {
			response = httpClient.execute(httpGet);
			String jsonResponse = EntityUtils.toString(response.getEntity());
			ObjectMapper objectMapper = new ObjectMapper();
			Map<String, String> result = objectMapper.readValue(jsonResponse, Map.class);
			String openid = result.get("openid");
//			String sessionKey = result.get("session_key");
			return openid;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";

	}

	/**
	 * 发起支付
	 *
	 * @param params 参数
	 * @param terminal 终端
	 * @return Object
	 */
	public Object prepay(PaymentValidate params, Integer terminal) {
		try {
			String openId = null;
			UserAuth userAuth = userAuthMapper.selectOne(new QueryWrapper<UserAuth>()
					.eq("user_id", params.getUserId())
					//					.eq("terminal", terminal)
					.last("limit 1"));

			if (StringUtils.isNotNull(userAuth)) {
				openId = userAuth.getOpenid();
			}
			// 单独处理小程序
			if(terminal == ClientEnum.MNP.getCode()) {
				if(null == userAuth ) {
					userAuth = new UserAuth();
					userAuth.setUserId(params.getUserId());
					userAuth.setMnpOpenid(getOpenidMnp(params.getCode()));
					userAuth.setCreateTime(System.currentTimeMillis() / 1000);
					userAuthMapper.insert(userAuth);
					openId = userAuth.getMnpOpenid();
				}else {
					if(StringUtils.isNotEmpty(userAuth.getMnpOpenid())) {
						openId = userAuth.getMnpOpenid();
					}else {
						openId = getOpenidMnp(params.getCode());
						userAuth.setMnpOpenid(openId);
						userAuth.setUpdateTime(System.currentTimeMillis() / 1000);
						userAuthMapper.updateById(userAuth);
					}
				}
			}

			// 定义支付返回结果
			Map<String, String> map = new LinkedHashMap<>();

			switch (params.getPayWay()) {
			case 1: // 余额支付
				String attach = params.getAttach();
				String orderSn = params.getOutTradeNo();
				this.handlePaidNotify(attach, orderSn, null);
				return Collections.emptyList();
			case 2: // 微信支付
				// 应付金额为0时
				if (params.getOrderAmount().compareTo(BigDecimal.ZERO) == 0) {
					this.handlePaidNotify(params.getAttach(), params.getOutTradeNo(), null);
					return Collections.emptyList();
				}
				if (terminal == ClientEnum.APK.getCode()) {
					Map<String, Object> createWxPayOrder = wxpayHandle.createWxPayOrder(params.getOutTradeNo(), params.getOrderAmount().toPlainString(), params.getDescription(), WxPayConfigUtils.MALLNOTIFYURL);
					return createWxPayOrder;
				}
				if(terminal == ClientEnum.PC.getCode()) {
					String qrCode = wxpayHandle.getQrCode(params.getOutTradeNo(), params.getOrderAmount().toPlainString(), params.getDescription(), WxPayConfigUtils.PCNOTIFYURL);
					return qrCode;
				}
				PaymentRequestV3 requestV3 = new PaymentRequestV3(); 
				requestV3.setTerminal(terminal);
				requestV3.setOpenId(openId);
				requestV3.setAttach(params.getAttach());
				requestV3.setOutTradeNo(params.getOutTradeNo());
				requestV3.setOrderAmount(params.getOrderAmount());
				requestV3.setDescription(params.getDescription());
				Object result = WxPayDriver.unifiedOrder(requestV3,"/api/pay/notifyMnp");
				if (terminal == ClientEnum.H5.getCode()) {
					Assert.notNull(params.getRedirectUrl(), "redirectUrl参数缺失");
					String redirectUrl = RequestUtils.domain() + "/mobile" + params.getRedirectUrl();
					String h5Url = result.toString() + "&redirect_url=" + URLEncoder.encode(redirectUrl, "UTF-8");
					map.put("url", h5Url);
					return map;
				}
				return result;
			case 3:
				// 应付金额为0时
				if (params.getOrderAmount().compareTo(BigDecimal.ZERO) == 0) {
					this.handlePaidNotify(params.getAttach(), params.getOutTradeNo(), null);
					return Collections.emptyList();
				}
				if (terminal == ClientEnum.APK.getCode()) {
					Map<String, Object> createAliPayOrder = alipayHandle.createAliPayOrder(params.getOutTradeNo(), params.getOrderAmount().toPlainString(), params.getDescription(), AliPayConfigUtils.MALLNOTIFYURL);
					return createAliPayOrder;
				}
				if(terminal == ClientEnum.PC.getCode()) {
					String qrCode = alipayHandle.getQrCode(params.getOutTradeNo(), params.getOrderAmount().toPlainString(), params.getDescription(), AliPayConfigUtils.MALLNOTIFYURL);
					return qrCode;
				}
				AliPaymentRequest requestAiliPay = new AliPaymentRequest();
				requestAiliPay.setOutTradeNo(params.getOutTradeNo());
				requestAiliPay.setOrderAmount(params.getOrderAmount());
				requestAiliPay.setDescription(params.getDescription());
				requestAiliPay.setAttach(params.getAttach());
				requestAiliPay.setUrl(params.getRedirectUrl());
				Object resultAliPay = AliPayDriver.unifiedOrder(requestAiliPay);
				map.put("form", resultAliPay.toString());
				return map;
			case 4: // 金币支付
				attach = params.getAttach();
				orderSn = params.getOutTradeNo();
				this.handlePaidNotify(attach, orderSn, null);
				return Collections.emptyList();
			}
		} catch (OperateException e) {
			throw new PaymentException(e.getMsg());
		} catch (Exception e) {
			throw new PaymentException(e.getMessage());
		}

		throw new PaymentException("支付发起异常");
	}

	/**
	 * 支付回调处理
	 *
	 * @author fzr
	 * @param attach 场景码
	 * @param outTradeNo 订单编号
	 * @param transactionId 流水号
	 */
	@Override
	public void handlePaidNotify(String attach, String outTradeNo, String transactionId) {
		// 开启事务
		TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
		try {
			switch (attach) {
			case "order":
				this.orderCallback(outTradeNo, transactionId);
				break;
			case "recharge":
				this.rechargeCallback(outTradeNo, transactionId);
				break;
			case "vip":
				VipRecord vipRecord = vipRecordMapper.selectOne(new LambdaQueryWrapper<VipRecord>().eq(VipRecord::getOrderSn, outTradeNo));
				vipRecord.setTradeNo(transactionId);
				vipRecord.setOrderUpdateTime(TimeUtils.timestamp());
				vipRecord.setOrderStatus(1);
				vipRecordMapper.updateById(vipRecord);
				handleAgentPayNotify(vipRecord.getRelatedId(), vipRecord.getUserId(),vipRecord.getId());
				break;
			}
			// 提交事务
			transactionManager.commit(transactionStatus);
		} catch (OperateException e) {
			// 事务回滚
			e.printStackTrace();
			transactionManager.rollback(transactionStatus);
			throw new OperateException(e.getMsg());
		} catch (Exception e) {
			// 事务回滚
			transactionManager.rollback(transactionStatus);
			e.printStackTrace();
			throw new OperateException(e.getMessage());
		}
	}


	/**
	 * 获取商户号
	 * @param payWay 支付方式
	 * @return 商户号
	 */
	@Override
	public Map<String, String> getMchId(Integer payWay) {
		DevPayConfig devPayConfig = devPayConfigMapper.selectOne(
				new QueryWrapper<DevPayConfig>()
				.eq("id", payWay)
				.last("limit 1"));
		Assert.notNull(devPayConfig, "支付方式不存在！");

		String env = YmlUtils.get("like.production");
		boolean envStatus = StringUtils.isNotNull(env) && env.equals("true");

		Map<String, String> params = MapUtils.jsonToMap(devPayConfig.getParams().toString());
		LinkedHashMap<String, String> map = new LinkedHashMap<>();
		map.put("mch_id", envStatus ? "******" : params.getOrDefault("mch_id", ""));
		return map;
	}

	/**
	 * 余额充值回调
	 *
	 * @author fzr
	 * @param outTradeNo 订单号
	 * @param transactionId 流水号
	 */
	private void rechargeCallback(String outTradeNo, String transactionId) {
		for (int i=0; i<=0; i++) {
			RechargeOrder rechargeOrder = rechargeOrderMapper.selectOne(
					new QueryWrapper<RechargeOrder>()
					.eq("order_sn", outTradeNo)
					.last("limit 1"));

			if (StringUtils.isNull(rechargeOrder)) {
				log.error("充值订单不存在: {} : {}", outTradeNo, transactionId);
				break;
			}

			if (rechargeOrder.getPayStatus().equals(PaymentEnum.OK_PAID.getCode())) {
				log.error("充值订单已支付: {} : {}", outTradeNo, transactionId);
				break;
			}

			rechargeOrder.setPayStatus(1);
			rechargeOrder.setTransactionId(transactionId);
			rechargeOrder.setPayTime(System.currentTimeMillis() / 1000);
			rechargeOrder.setUpdateTime(System.currentTimeMillis() / 1000);
			rechargeOrderMapper.updateById(rechargeOrder);

			User user = userMapper.selectById(rechargeOrder.getUserId());
			user.setMoney(user.getMoney().add(rechargeOrder.getOrderAmount()));
			user.setUpdateTime(System.currentTimeMillis() / 1000);
			userMapper.updateById(user);

			logMoneyMapper.add(rechargeOrder.getUserId(),
					LogMoneyEnum.UM_INC_RECHARGE.getCode(),
					rechargeOrder.getOrderAmount(),
					rechargeOrder.getId(),
					rechargeOrder.getOrderSn(),
					"用户充值余额", null);
		}
	}

	/**
	 * 订单支付回调
	 *
	 * @author mjf
	 * @param outTradeNo String
	 * @param transactionId String
	 */
	private void orderCallback(String outTradeNo, String transactionId) {
		Order order = orderMapper.selectOne(
				new QueryWrapper<Order>()
				.eq("order_sn", outTradeNo)
				.last("limit 1"));
		List<Order> list = new ArrayList<>();
		list = orderMapper.selectList(new QueryWrapper<Order>()
				.eq("is_delete", 0)
				.eq("main_id", order.getOrderSn()));

		if (StringUtils.isNull(order)) {
			log.error("订单不存在: {} : {}", outTradeNo, transactionId);
			throw new OperateException("订单不存在");
		}

		if (order.getPayIs().equals(PaymentEnum.OK_PAID.getCode())) {
			log.error("订单已支付: {} : {}", outTradeNo, transactionId);
			throw new OperateException("订单已支付");
		}
		User user = userMapper.selectById(order.getUserId());
		// 余额支付方式时扣减余额，记录日志
		if (order.getPayWay().equals(PaymentEnum.WALLET_PAY.getCode())) {
			if (user.getEarnings().compareTo(order.getNeedPayMoney()) < 0) {
				log.error("余额不足: {} : {}", outTradeNo, transactionId);
				throw new OperateException("余额不足");
			}
			user.setEarnings(user.getEarnings().subtract(order.getNeedPayMoney()));
			user.setUpdateTime(System.currentTimeMillis() / 1000);
			userMapper.updateById(user);
			logEarningsMapper.dec(order.getUserId(), 
					LogMoneyEnum.UE_DEC_GOODS.getCode(), order.getNeedPayMoney(), order.getId(), order.getOrderSn(),
					"余额支付订单", null);
		}
		// 金币支付 扣减金币 记录日志
		if(order.getPayWay().equals(PaymentEnum.GOLD_PAY.getCode())) {
			BigDecimal multiply = order.getNeedPayMoney().multiply(new BigDecimal("100"));
			if (user.getIntegral().compareTo(multiply) < 0) {
				log.error("余额不足: {} : {}", outTradeNo, transactionId);
				throw new OperateException("金币不足");
			}
			user.setIntegral(user.getIntegral().subtract(multiply));
			user.setUpdateTime(System.currentTimeMillis() / 1000);
			userMapper.updateById(user);
			logIntegralMapper.add(
					order.getUserId(), LogMoneyEnum.UI_DEC_GOODS.getCode(), multiply, order.getId(), order.getOrderSn(), "金币购物扣减", "");
		}
		for(Order order2 : list){
			order2.setPayIs(1);
			order2.setOrderStatus(OrderEnum.ORDER_STATUS_WAIT_DELIVER.getCode());
			order2.setTransactionId(transactionId);
			order2.setPayMoney(order2.getNeedPayMoney());
			order2.setPayTime(System.currentTimeMillis() / 1000);
			order2.setUpdateTime(System.currentTimeMillis() / 1000);
			orderMapper.updateById(order2);
		}
		// 更新订单信息
		order.setPayIs(1);
		order.setOrderStatus(OrderEnum.ORDER_STATUS_WAIT_DELIVER.getCode());
		order.setTransactionId(transactionId);
		order.setPayMoney(order.getNeedPayMoney());
		order.setPayTime(System.currentTimeMillis() / 1000);
		order.setUpdateTime(System.currentTimeMillis() / 1000);
		orderMapper.updateById(order);

		// 更新订单商品信息
		orderGoodsMapper.update(null, new UpdateWrapper<OrderGoods>()
				.eq("order_id", order.getId())
				.setSql("pay_money = need_pay_money"));

		// 更新商品销量
		List<Integer> goodsIdList = new ArrayList<Integer>();
		List<OrderGoods> orderGoodsList = orderGoodsMapper.selectList(new QueryWrapper<OrderGoods>()
				.eq("order_id", order.getId()));
		for (OrderGoods orderGoodsItem : orderGoodsList) {
			goodsMapper.update(null, new UpdateWrapper<Goods>()
					.eq("id", orderGoodsItem.getGoodsId())
					.setSql("sales_num = sales_num+" + orderGoodsItem.getGoodsNum()));
			goodsIdList.add(orderGoodsItem.getGoodsId());
		}
		// 是否是分佣产品
		//		handleCommission(goodsIdList, order.getUserId(),order,user);

		// 秒杀商品更新
		if (order.getOrderType().equals(OrderEnum.ORDER_SOURCE_SECKILL.getCode())) {
			iSeckillService.updateSeckillGoodsSales(order, orderGoodsList.get(0).getGoodsSkuId());
		}

		// 订单日志
		logOrderMapper.add(
				order.getId(),
				OrderLogEnum.TYPE_USER.getCode(),
				OrderLogEnum.CHANNEL_PAY_ORDER.getCode(),
				order.getUserId(),
				OrderLogEnum.CHANNEL_PAY_ORDER.getMsg()
				);

		if (order.getOrderType().equals(OrderEnum.ORDER_SOURCE_NORMAL.getCode())) {
			// 分销订单
			iDistributionService.addDistributionOrder(order.getId());
			// 更新分销等级
			iDistributionService.updateDistributionLevel(order.getUserId());
		}

		try {
			// 订单通知用户
			NoticeSmsVo UserParams = new NoticeSmsVo()
					.setScene(NoticeEnum.ORDER_PAY_NOTICE.getCode())
					.setMobile(order.getAddressMobile())
					.setExpire(900)
					.setParams(new String[]{
							"nickname:" + order.getAddressContact(),
							"order_sn:" + order.getOrderSn(),
							"order_money:" + order.getNeedPayMoney()
					});
			NoticeDriver.handle(UserParams);

			// 订单通知商家
			String platformMobile = ConfigUtils.get("contact", "mobile", "");
			if (StringUtils.isNotBlank(platformMobile)) {
				NoticeSmsVo params = new NoticeSmsVo()
						.setScene(NoticeEnum.SELLER_ORDER_PAY_NOTICE.getCode())
						.setMobile(platformMobile)
						.setExpire(900)
						.setParams(new String[]{
								"nickname:" + order.getAddressContact(),
								"order_sn:" + order.getOrderSn(),
								"order_money:" + order.getNeedPayMoney()
						});
				NoticeDriver.handle(params);
			}
		} catch (Exception ignored) {}
	}

	/**
	 * 	计算产品分佣
	 * @param goodsId
	 * @param userId
	 */
	private void handleCommission(List<Integer> goodsIds,Integer userId,Order order,User user) {
		List<Goods> goodsList = goodsMapper.selectList(new LambdaQueryWrapper<Goods>().in(Goods::getId, goodsIds)
				.select(Goods::getId,Goods::getSupplyPrice,Goods::getCashbackOrdinary,Goods::getCashbackSilver,Goods::getCashbackGold
						,Goods::getCashbackDiamond,Goods::getIsCashback,Goods::getReceiveVip,Goods::getCommissionType));
		if(CollectionUtil.isNotEmpty(goodsList)) {
			Integer userLevel = 1;
			// 修改用户VIP等级
			Distribution distribution = distributionMapper.selectOne(new LambdaQueryWrapper<Distribution>().eq(Distribution::getUserId, userId));
			if(null != distribution && null != distribution.getExpireTime() && distribution.getExpireTime() > TimeUtils.timestamp()) {
				userLevel = distribution.getLevelId();
			}
			for (Goods goods : goodsList) {
				// 是否可以领取会员
				/*if(goods.getReceiveVip() > 0) {
					goods.setReceiveVip(goods.getReceiveVip()+1);
					if(goods.getReceiveVip() >= userLevel) {
						boolean isTrue = true;
						if(null == distribution) {
							isTrue = false;
							distribution = new Distribution();
						}
						userLevel = goods.getReceiveVip();
						distribution.setLevelId(goods.getReceiveVip());
						distribution.setIsDistribution(1);
						distribution.setIsClose(0);
						distribution.setCreateTime(TimeUtils.timestamp());
						Date addDateForDays = TimeUtils.addDateForDays(new Date(), 365);
						String dateFormatDay = TimeUtils.dateFormatDay(addDateForDays);
						distribution.setExpireTime(TimeUtils.dateToTimestamp(dateFormatDay));
						if(isTrue) {
							distribution.setUpdateTime(TimeUtils.timestamp());
							distributionMapper.updateById(distribution);
						}else {
							distribution.setDistributionTime(TimeUtils.timestamp());
							distributionMapper.insert(distribution);
						}
					}
				}*/
				if(goods.getCommissionType() != 3) {
					// 分佣
					superiorCommission(userId, userLevel, goods, order,user);
				}
			}
		}
	}

	@Override
	public void handleAgentPayNotify(Integer levelId,Integer userId,Integer vipId) {
		// 获取到会员规格的id
		User user = userMapper.selectById(userId);
		if(null == user) {
			return;
		}
		DistributionLevel distributionLevel = distributionLevelMapper.selectById(levelId);
		if(null == distributionLevel) {
			return;
		}
		// 修改用户VIP等级
		Distribution distribution = distributionMapper.selectOne(new LambdaQueryWrapper<Distribution>().eq(Distribution::getUserId, userId));
		if(null == distribution) {
			distribution = new Distribution();
			distribution.setLevelId(levelId);
			distribution.setIsDistribution(1);
			distribution.setDistributionTime(TimeUtils.timestamp());
			distribution.setIsClose(0);
			distribution.setType(1);
			distribution.setCreateTime(TimeUtils.timestamp());
			Date addDateForDays = TimeUtils.addDateForDays(new Date(), 365);
			String dateFormatDay = TimeUtils.dateFormatDay(addDateForDays);
			distribution.setExpireTime(TimeUtils.dateToTimestamp(dateFormatDay));
			distributionMapper.insert(distribution);
		}else {
			Date date = new Date();
			if(distribution.getExpireTime() > TimeUtils.timestamp()) {
				date = TimeUtils.parse("yyyy-MM-dd HH:mm:ss", TimeUtils.timestampToDate(distribution.getExpireTime()));
			}
			Date addDateForDays = TimeUtils.addDateForDays(date, 365);
			String dateFormatDay = TimeUtils.dateFormatDay(addDateForDays);
			distribution.setExpireTime(TimeUtils.dateToTimestamp(dateFormatDay));
			distributionMapper.updateById(distribution);
		}
		VipRecord vip = new VipRecord();
		vip.setExtend(distribution.getExpireTime().toString());
		vip.setId(vipId);
		vipRecordMapper.insert(vip);
		BigDecimal price = distributionLevel.getPrice();// 会员单价
		// 是否存在上级/上上级/上上上级
		//		if(null != user.getFirstLeader() && user.getFirstLeader() > 0) {
		//			drawCommission(userId, user.getFirstLeader(), price, 1);
		//		}
		//		if(null != user.getSecondLeader() && user.getSecondLeader() > 0) {
		//			drawCommission(user.getFirstLeader(), user.getSecondLeader(), price, 2);
		//		}
		//		if(null != user.getThirdLeader() && user.getThirdLeader() > 0) {
		//			drawCommission(user.getSecondLeader(), user.getThirdLeader(), price, 3);
		//		}
		// 团队会员年费*80%现金
		teamCost(user.getFirstLeader(), price);

	}
	@Autowired
	EMServiceUtil eMServiceUtil;

	// 团队会员年费*80%现金
	public void teamCost(Integer userId,BigDecimal price) {
		Distribution distribution = distributionMapper.selectOne(new LambdaQueryWrapper<Distribution>().eq(Distribution::getUserId, userId));
		if(null != distribution && distribution.getLevelId() >= 5) {
			DistributionLevel distributionLevelSecond = distributionLevelMapper.selectById(distribution.getLevelId());
			BigDecimal _ratio = distributionLevelSecond.getSubordinateMember().divide(new BigDecimal("100"));
			BigDecimal multiply = price.multiply(_ratio).setScale(2,RoundingMode.HALF_UP);
			userMapper.update(null, new UpdateWrapper<User>()
					.eq("id", userId)
					.setSql("earnings = earnings+"+ multiply));
			logEarningsMapper.add(
					userId, LogMoneyEnum.UE_INC_GOODS.getCode(), multiply, 0, "", "团队用户年费利润", "");
			eMServiceUtil.sendNoticeOfReceipt(userMapper.getEmUserName(userId), "本次获得余额"+multiply);
		}
	}


	/**
	 * 	上级抽佣
	 * @param userId		用户ID
	 * @param userLevel		用户等级
	 * @param goods			商品信息	
	 * @param couponListId	优惠总金额
	 * @param user			用户信息
	 */
	public void superiorCommission(Integer userId,Integer userLevel,Goods goods,Order order,User user) {
		if(user.getFirstLeader() <= 0) {
			return;
		}
		Distribution distributionFirst = distributionMapper.selectOne(new LambdaQueryWrapper<Distribution>().eq(Distribution::getUserId, user.getFirstLeader()));
		if(distributionFirst == null) {
			return;
		}else if(distributionFirst.getLevelId() <= 2 || distributionFirst.getExpireTime() < TimeUtils.timestamp()){
			return;
		}
		DistributionLevel distributionLevelFirst = distributionLevelMapper.selectById(distributionFirst.getLevelId());
		BigDecimal firstAmount = distributionLevelFirst.getSuperiorAgent();
		BigDecimal secondAmount = BigDecimal.ZERO;
		if(user.getSecondLeader() > 0) {
			Distribution distributionSecond = distributionMapper.selectOne(new LambdaQueryWrapper<Distribution>().eq(Distribution::getUserId, user.getSecondLeader()));
			if(null != distributionSecond && distributionSecond.getLevelId() > 2 && distributionSecond.getExpireTime() > TimeUtils.timestamp()) {
				DistributionLevel distributionLevelSecond = distributionLevelMapper.selectById(distributionSecond.getLevelId());
				secondAmount = distributionLevelSecond.getSupSuperiorAgent();
			}
		}
		BigDecimal couponAmount = BigDecimal.ZERO;
		if(null == goods || null == goods.getId()) {
			throw new OperateException("产品有误");
		}
		OrderGoods orderGoods = orderGoodsMapper.selectOne(new LambdaQueryWrapper<OrderGoods>().eq(OrderGoods::getOrderId,order.getId()).eq(OrderGoods::getGoodsId, goods.getId())
				.select(OrderGoods::getGoodsPrice));
		if(null == orderGoods || null == orderGoods.getGoodsPrice()) {
			throw new OperateException("产品有误");
		}
		if(StringUtils.isNotEmpty(order.getCouponListId())) {
			if(!"0".equals(order.getCouponListId())){
				BigDecimal _m1 = order.getNeedPayMoney().subtract(order.getExpressMoney());
				BigDecimal _m2 = _m1.divide(order.getGoodsMoney(),2, RoundingMode.HALF_UP);
				BigDecimal _m3 = _m2.multiply(orderGoods.getGoodsPrice());
				couponAmount = orderGoods.getGoodsPrice().subtract(_m3);
			}
		}
		BigDecimal cashbackAmount = BigDecimal.ZERO;
		if(1 == userLevel) {
			cashbackAmount = goods.getCashbackOrdinary();
		}else if(2 == userLevel) {
			cashbackAmount = goods.getCashbackSilver();
		}else if(3 == userLevel) {
			cashbackAmount = goods.getCashbackGold();
		}else if(4 == userLevel) {
			cashbackAmount = goods.getCashbackDiamond();
		}
		BigDecimal _c = BigDecimal.ZERO;
		switch (goods.getCommissionType()) {
		case 1:
			// 按利润分佣产品 ： 产品售价-产品供货价-下单再返-领券优惠金额
			_c = orderGoods.getGoodsPrice().subtract(goods.getSupplyPrice()).subtract(cashbackAmount).subtract(couponAmount);
			break;
		case 2:
			// 按售价分佣产品 ： 产品售价-下单再返-领券优惠金额
			_c = orderGoods.getGoodsPrice().subtract(cashbackAmount).subtract(couponAmount);
			break;
		case 3:
			// TODO 月分佣 待沟通
			break;
		}
		User fUser = userMapper.selectById(user.getFirstLeader());
		BigDecimal fUserEarnings = fUser.getEarnings();
		if(fUserEarnings == null){
			fUserEarnings = BigDecimal.valueOf(0);
		}
		if(_c.compareTo(BigDecimal.ZERO) > 0) {
			if(firstAmount.compareTo(BigDecimal.ZERO) > 0) {
				BigDecimal _first = firstAmount.divide(new BigDecimal("100"));
				BigDecimal _earnings = _c.multiply(_first);
				fUserEarnings = fUserEarnings.add(_earnings).setScale(2,RoundingMode.HALF_UP);
				userMapper.update(null, new UpdateWrapper<User>()
						.eq("id", user.getFirstLeader())
						//.setSql("earnings = earnings+"+_earnings));
						.setSql("earnings = "+ fUserEarnings));
				logEarningsMapper.add(
						user.getFirstLeader(), LogMoneyEnum.UE_INC_GOODS.getCode(), _earnings, goods.getId(), order.getOrderSn(), "上级代理佣金", "");
			}
			if(secondAmount.compareTo(BigDecimal.ZERO) > 0) {
				BigDecimal _second = secondAmount.divide(new BigDecimal("100"));
				BigDecimal _earnings = _c.multiply(_second);
				fUserEarnings = fUserEarnings.add(_earnings).setScale(2,RoundingMode.HALF_UP);
				userMapper.update(null, new UpdateWrapper<User>()
						.eq("id", user.getSecondLeader())
						//.setSql("earnings = earnings+"+_earnings));
						.setSql("earnings = "+fUserEarnings));
				logEarningsMapper.add(
						user.getSecondLeader(), LogMoneyEnum.UE_INC_GOODS.getCode(), _earnings, goods.getId(), order.getOrderSn(), "上上级代理佣金", "");
			}
		}
	}

	/**
	 * 	抽佣
	 * @param superiorId		上级ID
	 * @param price				金额
	 * @param type				1=直属上级 2=上上级 3=上上上级
	 */
	public void drawCommission(Integer userId,Integer superiorId,BigDecimal price,Integer type) {
		Distribution distributionFirst = distributionMapper.selectOne(new LambdaQueryWrapper<Distribution>().eq(Distribution::getUserId, superiorId));
		if(null != distributionFirst && 1 == distributionFirst.getIsDistribution() && distributionFirst.getExpireTime() > TimeUtils.timestamp()) {
			DistributionLevel distributionLevelFirst = distributionLevelMapper.selectById(distributionFirst.getLevelId());
			if(null != distributionLevelFirst && distributionLevelFirst.getWeights() > 2) {
				User userFirst = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, superiorId).select(User::getId,User::getEarnings));
				if(null != userFirst) {
					String remark = "下级会员佣金";
					BigDecimal amount = distributionLevelFirst.getSubordinateMember();
					if(2 == type) {
						amount = distributionLevelFirst.getSuperiorAgent();
						remark = "下级会员抽佣";
					}else if(3 == type) {
						amount = distributionLevelFirst.getSupSuperiorAgent();
						remark = "下下级会员抽佣";
					}
					BigDecimal moneyFirst = price.subtract(amount);
					if(null == userFirst.getEarnings()) {
						userFirst.setEarnings(moneyFirst);
					}else {
						userFirst.setEarnings(userFirst.getEarnings().add(moneyFirst));
					}
					userMapper.updateById(userFirst);
					// 记录流水
					//					LogEarnings earnings = new LogEarnings();
					//					earnings.setUserId(superiorId);
					//					earnings.setChangeType(1);
					//					earnings.setChangeAmount(moneyFirst);
					//					earnings.setLeftAmount(userFirst.getEarnings());
					//					earnings.setRemark(remark);
					//					earnings.setAction(1);
					//					earnings.setExtra(String.valueOf(userId==null?0:userId));
					//					earnings.setCreateTime(TimeUtils.timestamp());
					//					logEarningsMapper.insert(earnings);

					// 余额日志
					//					logMoneyMapper.add(superiorId,
					//							LogMoneyEnum.UM_DEC_PAY_ORDER.getCode(),
					//							order.getNeedPayMoney(),
					//							order.getId(),
					//							order.getOrderSn(),
					//							"余额支付订单", null);
				}
			}
		}
	}

	@Resource
	private VipRecordMapper vipRecordMapper;


	@Override
	public AjaxResult<Object> payVip(Integer businessId, Integer payWay,String redirectUrl,Integer userId,String code,Integer terminal) throws Exception {
		DistributionLevel distributionLevel = distributionLevelMapper.selectById(businessId);
		if(null == distributionLevel) {
			return AjaxResult.failed("选择的VIP规格不存在");
		}
		String openId = null;
		UserAuth userAuth = userAuthMapper.selectOne(new QueryWrapper<UserAuth>()
				.eq("user_id", userId)
				//				.eq("terminal", terminal)
				.last("limit 1"));
		if (StringUtils.isNotNull(userAuth)) {
			openId = userAuth.getOpenid();
		}
		if(terminal == ClientEnum.MNP.getCode()) {
			if(null == userAuth ) {
				userAuth = new UserAuth();
				userAuth.setUserId(userId);
				userAuth.setMnpOpenid(getOpenidMnp(code));
				userAuth.setCreateTime(System.currentTimeMillis() / 1000);
				userAuthMapper.insert(userAuth);
				openId = userAuth.getMnpOpenid();
			}else {
				if(StringUtils.isNotEmpty(userAuth.getMnpOpenid())) {
					openId = userAuth.getMnpOpenid();
				}else {
					openId = getOpenidMnp(code);
					userAuth.setMnpOpenid(openId);
					userAuth.setUpdateTime(System.currentTimeMillis() / 1000);
					userAuthMapper.updateById(userAuth);
					
				}
			}
		}

		VipRecord record = new VipRecord();
		record.setUserId(userId);
		record.setOrderSn(ToolUtils.get());
		record.setPayWay(payWay);
		record.setRelatedId(distributionLevel.getId());
		record.setOrderAmount(distributionLevel.getPrice());
		record.setOrderCreateTime(TimeUtils.timestamp());
		record.setOrderStatus(0);
		record.setRemark("开通VIP("+distributionLevel.getName()+")");
		vipRecordMapper.insert(record);
		if(2 == payWay) { // 微信
			if (terminal == ClientEnum.APK.getCode()) {
				return AjaxResult.success(wxpayHandle.createWxPayOrder(record.getOrderSn(), record.getOrderAmount().toPlainString(), record.getRemark(),WxPayConfigUtils.VIPNOTIFYURL));
			}
			PaymentRequestV3 requestV3 = new PaymentRequestV3();
			requestV3.setTerminal(terminal);
			requestV3.setOpenId(openId);
			requestV3.setAttach("vip");
			requestV3.setOutTradeNo(record.getOrderSn());
			requestV3.setOrderAmount(record.getOrderAmount());
			requestV3.setDescription(record.getRemark());
			Object result = WxPayDriver.unifiedOrder(requestV3,"/api/pay/notifyMnp");
			if (terminal == ClientEnum.H5.getCode()) {
				Assert.notNull(redirectUrl, "redirectUrl参数缺失");
				redirectUrl = RequestUtils.domain() + "/mobile" + redirectUrl;
				String h5Url = result.toString() + "&redirect_url=" + URLEncoder.encode(redirectUrl, "UTF-8");
				Map<String, String> map = new LinkedHashMap<>();
				map.put("url", h5Url);
				return AjaxResult.success(map);
			}
			return AjaxResult.success(result);

		}else if(3 == payWay) { // 支付宝
			return AjaxResult.success(alipayHandle.createAliPayOrder(record.getOrderSn(), record.getOrderAmount().toPlainString(), record.getRemark(), AliPayConfigUtils.VIPNOTIFYURL));
		}
		return AjaxResult.failed("未知支付方式");
	}

	@Override
	@Transactional
	public String notifyFromAlipay(Map<String, String> params) {
		//验证签名
		try {
			boolean flag = AlipaySignature.rsaCertCheckV1(params, AliPayConfigUtils.PUBLICCERTRAS2PATH, "UTF-8", "RSA2");
			if (flag) {
				String tradeStatus = params.get("trade_status");
				//签名验证通过,验证支付结果
				if ("TRADE_FINISHED".equals(tradeStatus)
						|| "TRADE_SUCCESS".equals(tradeStatus)) {
					String orderNo = params.get("out_trade_no");
					String tradeNo = params.get("trade_no");
					String totalAmount = params.get("total_amount");

					System.out.println("支付宝回调成功============================================tradeStatus："+tradeStatus);
					//以上两个状态代表支付成功
					VipRecord vipRecord = vipRecordMapper.selectOne(new LambdaQueryWrapper<VipRecord>().eq(VipRecord::getOrderSn, orderNo));
					if(null == vipRecord) {
						log.error("订单号不存在,支付失败 :" + orderNo);
						return "fail";
					}
					if(1 == vipRecord.getOrderStatus()) {
						log.error("订单已支付,忽略重复调用 :" + orderNo);
						return "success";
					}
					vipRecord.setTradeNo(tradeNo);
					vipRecord.setActualAmount(new BigDecimal(totalAmount));
					vipRecord.setOrderUpdateTime(TimeUtils.timestamp());
					vipRecord.setOrderStatus(1);
					vipRecordMapper.updateById(vipRecord);
					handleAgentPayNotify(vipRecord.getRelatedId(), vipRecord.getUserId(), vipRecord.getId());
				}
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return "fail";
	}

	@Override
	@Transactional
	public String notifyFromWxpay(String notifyStr) {
		String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
		try {
			// 转换成map
			Map<String, String> resultMap = WXPayUtil.xmlToMap(notifyStr);
			WXPay wxPay = new WXPay(wxConfig);
			if (wxPay.isPayResultNotifySignatureValid(resultMap)) {
				String returnCode = resultMap.get("return_code");  //状态
				String orderNo = resultMap.get("out_trade_no");//商户订单号
				String tradeNo = resultMap.get("transaction_id"); //微信订单号
				String totalfee = resultMap.get("total_fee"); //微信订单号
				if (returnCode.equals("SUCCESS")) {
					//支付成功
					VipRecord vipRecord = vipRecordMapper.selectOne(new LambdaQueryWrapper<VipRecord>().eq(VipRecord::getOrderSn, orderNo));
					if(null == vipRecord) {
						log.error("订单号不存在,支付失败 :" + orderNo);
						return "fail";
					}
					if(1 == vipRecord.getOrderStatus()) {
						log.error("订单已支付,忽略重复调用 :" + orderNo);
						return "success";
					}
					vipRecord.setTradeNo(tradeNo);
					vipRecord.setActualAmount(new BigDecimal(String.valueOf(Double.valueOf(totalfee) / 100)));
					vipRecord.setOrderUpdateTime(TimeUtils.timestamp());
					vipRecord.setOrderStatus(1);
					vipRecordMapper.updateById(vipRecord);
					handleAgentPayNotify(vipRecord.getRelatedId(), vipRecord.getUserId(), vipRecord.getId());
					xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return xmlBack;
	}
}
